package com.shelpe.services.sinbad.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaBuilder.In;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.shelpe.services.sinbad.controller.dto.RankItem;
import com.shelpe.services.sinbad.controller.dto.RankingDto;
import com.shelpe.services.sinbad.controller.dto.RankingView;
import com.shelpe.services.sinbad.controller.dto.vo.KeywordRanking;
import com.shelpe.services.sinbad.controller.sinbad.RankingController.RankingPriceDto;
import com.shelpe.services.sinbad.dto.KeywordDto;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.Campaign;
import com.shelpe.services.sinbad.entity.jpa.Tactics;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.WantRank;
import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.model.KeywordExample;
import com.shelpe.services.sinbad.readdao.KeywordMapper;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;
import com.shelpe.services.sinbad.repository.jpa.TacticsRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.repository.jpa.WantRankRepository;
import com.shelpe.services.sinbad.service.simbaproxy.LexiconClient;

@Service
public class RankingService {
	public final static Predicate[] TEMPLATE = new Predicate[0];

	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private CampaignRepository campaignRepository;
	@Autowired
	private KeywordMapper keywordMapper;
	@Autowired
	private TacticsRepository tacticsRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private WantRankRepository wantRankRepository;
	@Autowired
	private LexiconClient lexiconClient;

	public final static String DEVICE_pc = "pc";
	public final static String DEVICE_mobile = "mobile";
	public final static int DEVICE_PC = 2;
	public final static int DEVICE_MOBILE = 1;

	public RankingPriceDto findRankingPrice(long adgroupID) {
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "该推广组不存在");

		String catIDs[] = adgroup.getCategoryIDs().split(" ");
		LexiconClient.EffectMetricResult res = this.lexiconClient
				.findCategoryInsightMetric(NumberUtils.toLong(catIDs[catIDs.length - 1]));

		RankingPriceDto dto = new RankingPriceDto();
		if (res != null && res.getMetric() != null && res.getMetric().getCpc() > 0.0f) {
			if (res.getMetric().getCpc() * 2 > 4.0f) {
				dto.setPrice((int) 400.0f);
			} else {
				dto.setPrice((int) res.getMetric().getCpc() * 2);
			}
		} else {
			dto.setPrice((int) 400.0f);
		}
		return dto;
	}

	public List<RankingDto> createRanking(long userID, RankItem dto) {
		Assert.notNull(dto.getPremium());

		dto.setName("新版卡位");
		List<Tactics> tacticses = new ArrayList<Tactics>();
		for (KeywordRanking ranking : dto.getKeywords()) {
			Tactics tactics = dto.to();
			tactics.setKeywordIDs(String.valueOf(ranking.getKeywordID()));
			tactics.setUserID(userID);
			tactics.setCreatedTime(new Date());
			tactics.setCreateTime(new Date());
			tactics.setModifiedTime(new Date());
			tacticses.add(tactics);
		}
		this.tacticsRepository.save(tacticses);

		Map<Long, Long> map = new HashMap<Long, Long>();
		for (Tactics tactics : tacticses) {
			map.put(NumberUtils.toLong(tactics.getKeywordIDs()), tactics.getTacticsID());
		}

		List<WantRank> ranks = new ArrayList<WantRank>();
		for (KeywordRanking ranking : dto.getKeywords()) {
			if (map.get(ranking.getKeywordID()) == null) {
				continue;
			}
			WantRank rank = new WantRank();
			rank.setTacticsID(map.get(ranking.getKeywordID()));
			rank.from(ranking);
			ranks.add(rank);
		}
		this.wantRankRepository.save(ranks);

		List<RankingDto> retDtos = new ArrayList<RankingDto>();
		for (Tactics tactics : tacticses) {
			RankingDto retDto = new RankingDto();
			retDto.from(tactics);
			retDtos.add(retDto);
		}

		return retDtos;
	}

	public RankingDto updateRanking(long rankingID, RankingDto dto) {
		Tactics po = this.tacticsRepository.findOne(rankingID);
		Assert.notNull(po, "该卡位不存在");
		User user = this.userRepository.findOne(po.getUserID());
		Assert.notNull(user, "该用户不存在");

		int originalHeighestPrice = po.getHeighestPrice();

		dto.to(po);
		po.setModifiedTime(new Date());
		po.setLastModifiedTime(new Date());
		this.tacticsRepository.save(po);

		WantRank.WantRankPK pk = new WantRank.WantRankPK();
		pk.setKeywordID(NumberUtils.toLong(po.getKeywordIDs()));
		pk.setTacticsID(po.getTacticsID());
		WantRank rank = this.wantRankRepository.findOne(pk);
		// 期望排名的修改
		boolean needWantRank = false;
		if (rank != null) {
			if (dto.getWantRank() != null) {
				rank.setWantRank(dto.getWantRank());
				needWantRank = true;
			}
			if (dto.getHeighestPrice() > 0 && dto.getHeighestPrice() > originalHeighestPrice
					&& rank.getDoing() == WantRank.Doing.overflowed) {
				rank.setDoing(WantRank.Doing.executable);
				needWantRank = true;
			}
			if (needWantRank) {
				this.wantRankRepository.save(rank);
			}
		}

		RankingDto retDto = new RankingDto();
		retDto.from(po);
		return retDto;
	}

	public RankingDto findRanking(long rankingID) {
		Tactics po = this.tacticsRepository.findOne(rankingID);
		Assert.notNull(po, "该卡位不存在");
		RankingDto retDto = new RankingDto();
		retDto.from(po);

		WantRank.WantRankPK pk = new WantRank.WantRankPK();
		pk.setKeywordID(NumberUtils.toLong(po.getKeywordIDs()));
		pk.setTacticsID(po.getTacticsID());
		WantRank wantRank = this.wantRankRepository.findOne(pk);
		if (wantRank != null) {
			retDto.setWantRank(wantRank.getWantRank());
		}
		return retDto;
	}

	public List<RankingDto> updateRanking(long userID, List<RankItem> dtos) {
		User user = this.userRepository.findOne(userID);
		Assert.notNull(user, "该用户不存在");

		List<Long> rankingIDs = new ArrayList<Long>();
		for (RankItem dto : dtos) {
			if (rankingIDs.indexOf(dto.getRankingID()) == -1) {
				rankingIDs.add(dto.getRankingID());
			}
		}
		List<Tactics> pos = this.tacticsRepository.findAll(new Specification<Tactics>() {
			@Override
			public Predicate toPredicate(Root<Tactics> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				predicates.add(cb.equal(root.get("userID"), userID));
				if (rankingIDs != null && rankingIDs.size() > 0) {
					In<Long> ins = cb.in(root.<Long>get("tacticsID"));
					for (long RankingID : rankingIDs) {
						ins.value(RankingID);
					}
					predicates.add(ins);
				}
				return cb.and(predicates.toArray(TEMPLATE));
			}
		});

		List<RankingDto> retDtos = new ArrayList<RankingDto>();
		if (pos == null || pos.size() == 0) {
			return retDtos;
		}
		Map<Long, Tactics> map = new HashMap<Long, Tactics>();
		for (Tactics po : pos) {
			map.put(po.getTacticsID(), po);
		}

		for (RankItem dto : dtos) {
			Tactics po = map.get(dto.getRankingID());
			if (po != null) {
				dto.to(po);
				po.setModifiedTime(new Date());
				po.setLastModifiedTime(new Date());
				RankingDto retDto = new RankingDto();
				retDto.from(po);
				retDtos.add(retDto);
			}
		}
		this.tacticsRepository.save(pos);

		return retDtos;
	}

	public List<RankingDto> deleteRanking(long userID, List<Long> rankingIDs) {
		User user = this.userRepository.findOne(userID);
		Assert.notNull(user, "该用户不存在");

		List<Tactics> pos = this.tacticsRepository.findAll(new Specification<Tactics>() {
			@Override
			public Predicate toPredicate(Root<Tactics> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				predicates.add(cb.equal(root.get("userID"), userID));
				if (rankingIDs != null && rankingIDs.size() > 0) {
					In<Long> ins = cb.in(root.<Long>get("tacticsID"));
					for (long RankingID : rankingIDs) {
						ins.value(RankingID);
					}
					predicates.add(ins);
				}

				return cb.and(predicates.toArray(TEMPLATE));
			}
		});

		List<RankingDto> dtos = new ArrayList<RankingDto>();
		for (Tactics po : pos) {
			RankingDto dto = new RankingDto();
			dto.from(po);
			dtos.add(dto);
		}
		this.tacticsRepository.delete(pos);
		return dtos;
	}

	public void checkKeywordRanking(long userID, List<KeywordDto> dtos) {
		List<Tactics> pos = this.tacticsRepository.findAll(new Specification<Tactics>() {
			@Override
			public Predicate toPredicate(Root<Tactics> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				predicates.add(cb.equal(root.get("userID"), userID));
				return cb.and(predicates.toArray(TEMPLATE));
			}
		});
		List<Long> keywordIDs = new ArrayList<Long>();
		Map<Long, Tactics> map = new HashMap<Long, Tactics>();
		if (pos != null && pos.size() > 0) {
			for (Tactics po : pos) {
				String arr[] = po.getKeywordIDs().split(",");
				Long[] longs = new Long[arr.length];
				for (int i = 0; i < arr.length; i++) {
					longs[i] = Long.parseLong(arr[i]);
				}
				List<Long> strs = java.util.Arrays.asList(longs);
				for (long str : strs) {
					map.put(str, po);
					if (keywordIDs.indexOf(str) == -1) {
						keywordIDs.add(str);
					}
				}
			}

			for (KeywordDto dto : dtos) {
				dto.setRankingNum(pos.size());
				if (keywordIDs.contains(dto.getKeywordID())) {
					dto.setRankingNow(true);
					for (long keywordID : keywordIDs) {
						Tactics po = map.get(keywordID);
						if (po != null) {
							dto.setRankingID(po.getTacticsID());
							if (DEVICE_MOBILE == po.getDevice()) {
								dto.setRankingDevice(DEVICE_mobile);
							} else {
								dto.setRankingDevice(DEVICE_pc);
							}
						}
					}

				}
			}
		}
	}

	public List<RankingView> findRankings(long userID, boolean needDetail) {
		User user = this.userRepository.findOne(userID);
		Assert.notNull(user, "该用户不存在");
		List<Tactics> pos = this.tacticsRepository.findAll(new Specification<Tactics>() {
			@Override
			public Predicate toPredicate(Root<Tactics> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = cb.equal(root.get("userID"), userID);
				return p;
			}
		});

		List<Long> keywordIDs = new ArrayList<Long>();
		List<Long> rankingIDs = new ArrayList<Long>();
		Map<Long, Tactics> mapTactics = new HashMap<Long, Tactics>();
		for (Tactics po : pos) {
			if (rankingIDs.indexOf(po.getTacticsID()) == -1) {
				rankingIDs.add(po.getTacticsID());
			}
			String arr[] = po.getKeywordIDs().split(",");
			Long[] longs = new Long[arr.length];
			for (int i = 0; i < arr.length; i++) {
				longs[i] = Long.parseLong(arr[i]);
			}
			List<Long> str = java.util.Arrays.asList(longs);
			for (long keywordID : str) {
				if (keywordIDs.indexOf(keywordID) == -1) {
					keywordIDs.add(keywordID);
					mapTactics.put(keywordID, po);
				}
			}
		}

		// 获取期望排名
		Map<WantRank.WantRankPK, WantRank> wantRankMap = new HashMap<WantRank.WantRankPK, WantRank>();
		List<WantRank> wantRanks = this.wantRankRepository.findByTacticsIDIn(rankingIDs);
		for (WantRank wantRank : wantRanks) {
			WantRank.WantRankPK pk = new WantRank.WantRankPK();
			pk.setKeywordID(wantRank.getKeywordID());
			pk.setTacticsID(wantRank.getTacticsID());
			wantRankMap.put(pk, wantRank);
		}

		// 获取所有的关键词
		List<RankingView> dtos = new ArrayList<RankingView>();
		if (keywordIDs == null || keywordIDs.size() == 0) {
			return dtos;
		}
		KeywordExample ke = new KeywordExample();
		ke.setUserId(userID);
		ke.createCriteria().andKeywordIdIn(keywordIDs);
		List<Keyword> keywords = this.keywordMapper.selectByExample(ke);

		if (keywords == null || keywords.size() == 0) {
			return dtos;
		}

		// 获取推广组相关信息
		List<Long> adgroupIDs = new ArrayList<Long>();
		Map<Long, Keyword> mapKeyword = new HashMap<Long, Keyword>();
		for (Keyword kw : keywords) {
			mapKeyword.put(kw.getKeywordId(), kw);
			if (adgroupIDs.indexOf(kw.getAdgroupId()) == -1) {
				adgroupIDs.add(kw.getAdgroupId());
			}
		}
		List<Adgroup> adgroups = this.adgroupRepository.findByAutoIDIn(adgroupIDs);
		if (adgroups == null || adgroups.size() == 0) {
			return dtos;
		}
		Map<Long, Adgroup> mapAdgroup = new HashMap<Long, Adgroup>();
		// 获取计划相关信息
		List<Long> campaignIDs = new ArrayList<Long>();
		for (Adgroup adgroup : adgroups) {
			if (campaignIDs.indexOf(adgroup.getCampaignID()) == -1) {
				campaignIDs.add(adgroup.getCampaignID());
			}
			mapAdgroup.put(adgroup.getAutoID(), adgroup);
		}
		List<Campaign> campaigns = this.campaignRepository.findByAutoIDIn(campaignIDs);
		if (campaigns == null || campaigns.size() == 0) {
			return dtos;
		}
		Map<Long, Campaign> mapCampaign = new HashMap<Long, Campaign>();
		for (Campaign campaign : campaigns) {
			mapCampaign.put(campaign.getAutoID(), campaign);
		}

		for (long keywordID : keywordIDs) {
			Tactics tactics = mapTactics.get(keywordID);
			Keyword kw = mapKeyword.get(keywordID);
			if (tactics == null || kw == null) {
				continue;
			}
			WantRank.WantRankPK pk = new WantRank.WantRankPK();
			pk.setKeywordID(keywordID);
			pk.setTacticsID(tactics.getTacticsID());
			WantRank wantRank = wantRankMap.get(pk);
			Adgroup adgroup = mapAdgroup.get(kw.getAdgroupId());
			if (adgroup == null || wantRank == null) {
				continue;
			}
			Campaign campaign = mapCampaign.get(adgroup.getCampaignID());
			if (campaign == null) {
				continue;
			}
			RankingView dto = new RankingView();
			dto.from(campaign, adgroup, kw, tactics, wantRank);
			if (needDetail) {
				dto.from(tactics);
			}
			dtos.add(dto);
		}
		return dtos;
	}
}
